package com.jianjun.project.monitor.job;

import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.Method;
import cn.hutool.poi.excel.ExcelUtil;
import cn.hutool.poi.excel.ExcelWriter;
import com.jfinal.aop.Inject;
import com.jfinal.core.Controller;
import com.jfinal.core.Path;
import com.jfinal.kit.JsonKit;
import com.jfinal.plugin.activerecord.Model;
import com.jfinal.plugin.activerecord.Page;
import com.jianjun.common.constant.Constants;
import com.jianjun.common.constant.HttpStatus;
import com.jianjun.common.util.SecurityUtils;
import com.jianjun.common.util.job.ScheduleUtils;
import com.jianjun.framework.web.domain.AjaxResult;
import com.jianjun.framework.web.interceptor.DataScope;
import com.jianjun.framework.web.page.TableDataInfo;
import com.jianjun.framework.web.render.ExcelWriterRender;
import com.jianjun.project.common.model.SysJob;

import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 调度任务信息操作处理
 *
 * @author source
 * 为了兼容Quartz表达式，同时支持6位和7位表达式，其中：
 *   当为6位时，第一位表示秒 ，范围0~59，但是第一位不做匹配
 *   当为7位时，最后一位表示年 ，范围1970~2099，但是第7位不做解析，也不做匹配
 */
@Path(value = "/monitor/job")
public class SysJobController extends Controller {

    @Inject
    SysJobService jobService;

    /**
     * 查询定时任务列表
     */
    @DataScope(permission = "monitor:job:list")
    public void list() {
        SysJob job = JsonKit.parse(getKv().toJson(), SysJob.class);
        Page<SysJob> page = jobService.paginate(job);
        TableDataInfo rspData = new TableDataInfo();
        rspData.setCode(HttpStatus.SUCCESS);
        rspData.setMsg("查询成功");
        rspData.setRows(page.getList());
        rspData.setTotal(page.getTotalRow());
        renderJson(rspData);
    }

    /**
     * 导出定时任务列表
     */
    @DataScope(permission = "monitor:job:export")
    public void export() {
        SysJob job = JsonKit.parse(getKv().toJson(), SysJob.class);
        List<SysJob> list = jobService.selectJobList(job);
        List<Map<String, Object>> mapList = list.stream().map(Model::toMap).collect(Collectors.toList());
        ExcelWriter writer = ExcelUtil.getWriter(true);
        writer.write(mapList, true);
        render(new ExcelWriterRender(writer, job.getClass().getSimpleName()));
    }

    @DataScope(permission = "monitor:job:query,monitor:job:add,monitor:job:edit,monitor:job:remove")
    public void index() {
        String method = getRequest().getMethod();
        //查询
        if (Method.GET.name().equals(method)) {
            Long jobId = getParaToLong();
            renderJson(AjaxResult.success(jobService.selectJobById(jobId)));
        }
        //新增
        if (Method.POST.name().equals(method)) {
            SysJob job = JsonKit.parse(getRawData(), SysJob.class);
            if (!jobService.checkCronExpressionIsValid(job.getCronExpression())) {
                renderJson(AjaxResult.error("新增任务'" + job.getJobName() + "'失败，Cron表达式不正确"));
                return;
            } else if (StrUtil.containsIgnoreCase(job.getInvokeTarget(), Constants.LOOKUP_RMI)) {
                renderJson(AjaxResult.error("新增任务'" + job.getJobName() + "'失败，目标字符串不允许'rmi'调用"));
                return;
            } else if (StrUtil.containsAnyIgnoreCase(job.getInvokeTarget(), new String[]{Constants.LOOKUP_LDAP, Constants.LOOKUP_LDAPS})) {
                renderJson(AjaxResult.error("新增任务'" + job.getJobName() + "'失败，目标字符串不允许'ldap(s)'调用"));
                return;
            } else if (StrUtil.containsAnyIgnoreCase(job.getInvokeTarget(), new String[]{Constants.HTTP, Constants.HTTPS})) {
                renderJson(AjaxResult.error("新增任务'" + job.getJobName() + "'失败，目标字符串不允许'http(s)'调用"));
                return;
            } else if (StrUtil.containsAnyIgnoreCase(job.getInvokeTarget(), Constants.JOB_ERROR_STR)) {
                renderJson(AjaxResult.error("新增任务'" + job.getJobName() + "'失败，目标字符串存在违规"));
                return;
            } else if (!ScheduleUtils.whiteList(job.getInvokeTarget())) {
                renderJson(AjaxResult.error("新增任务'" + job.getJobName() + "'失败，目标字符串不在白名单内"));
                return;
            }
            job.setCreateBy(SecurityUtils.getUsername());
            renderJson(AjaxResult.success(jobService.insertJob(job)));
        }
        //修改
        if (Method.PUT.name().equals(method)) {
            SysJob job = JsonKit.parse(getRawData(), SysJob.class);
            if (!jobService.checkCronExpressionIsValid(job.getCronExpression())) {
                renderJson(AjaxResult.error("修改任务'" + job.getJobName() + "'失败，Cron表达式不正确"));
                return;
            } else if (StrUtil.containsIgnoreCase(job.getInvokeTarget(), Constants.LOOKUP_RMI)) {
                renderJson(AjaxResult.error("修改任务'" + job.getJobName() + "'失败，目标字符串不允许'rmi'调用"));
                return;
            } else if (StrUtil.containsAnyIgnoreCase(job.getInvokeTarget(), new String[]{Constants.LOOKUP_LDAP, Constants.LOOKUP_LDAPS})) {
                renderJson(AjaxResult.error("修改任务'" + job.getJobName() + "'失败，目标字符串不允许'ldap(s)'调用"));
                return;
            } else if (StrUtil.containsAnyIgnoreCase(job.getInvokeTarget(), new String[]{Constants.HTTP, Constants.HTTPS})) {
                renderJson(AjaxResult.error("修改任务'" + job.getJobName() + "'失败，目标字符串不允许'http(s)'调用"));
                return;
            } else if (StrUtil.containsAnyIgnoreCase(job.getInvokeTarget(), Constants.JOB_ERROR_STR)) {
                renderJson(AjaxResult.error("修改任务'" + job.getJobName() + "'失败，目标字符串存在违规"));
                return;
            } else if (!ScheduleUtils.whiteList(job.getInvokeTarget())) {
                renderJson(AjaxResult.error("修改任务'" + job.getJobName() + "'失败，目标字符串不在白名单内"));
                return;
            }
            job.setUpdateBy(SecurityUtils.getUsername());
            renderJson(AjaxResult.success(jobService.updateJob(job)));
        }
        //删除
        if (Method.DELETE.name().equals(method)) {
            jobService.deleteJobByIds(Convert.toLongArray(getPara()));
            renderJson(AjaxResult.success());
        }
    }

    /**
     * 定时任务状态修改
     */
    @DataScope(permission = "monitor:job:changeStatus")
    public void changeStatus() {
        SysJob job = JsonKit.parse(getRawData(), SysJob.class);
        SysJob newJob = jobService.selectJobById(job.getJobId());
        newJob.setStatus(job.getStatus());
        renderJson(AjaxResult.ajax(jobService.changeStatus(newJob)));
    }

    /**
     * 定时任务立即执行一次
     */
    @DataScope(permission = "monitor:job:changeStatus")
    public void run() {
        SysJob job = JsonKit.parse(getRawData(), SysJob.class);
        SysJob newJob = jobService.selectJobById(job.getJobId());
        boolean result = jobService.run(newJob);
        renderJson(result ? AjaxResult.success() : AjaxResult.error("任务不存在或已过期！"));
    }
}
